home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Interactive Reference Guide
/
C-C++ Interactive Reference Guide.iso
/
c_ref
/
csource5
/
357_01
/
cstar1.exe
/
SYS.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-18
|
15KB
|
776 lines
/*
C* -- System Interface Module with IO redirection support.
Source: cppsys.c
Started: October 7, 1985
Version:
April 2, 1987
March 7, 1989
PUBLIC DOMAIN SOFTWARE
The CSTAR program was placed in the public domain on June 15, 1991,
by its author and sole owner,
Edward K. Ream
1617 Monroe Street
Madison, WI 53711
(608) 257-0802
CSTAR may be used for any commercial or non-commercial purpose.
See cstar.h or cstar.c for a DISCLAIMER OF WARRANTIES.
*/
#include "cstar.h"
/* Define STANDARD_C if the Compiler uses the standard C library. */
#define STANDARD_C 1
#ifdef MICRO_SOFT
#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <io.h>
#endif
#ifdef TURBOC
#include <fcntl.h>
#include <sys\stat.h>
#include <io.h>
#include <dos.h>
#endif
/*
Externally visible routines:
*/
void sysabort (void);
void sysnext (void);
void syspush (int c);
void sysspush (char *s);
void sysiclose (void);
bool sysopen (char * name);
bool syscreat (char * name);
void sysoclose (void);
void sysnlput (void);
void syscput (char c);
void syssput (char * s);
void sysend (void);
void sysinit (void);
int syscsts (void);
/*
Internal routines:
*/
static void sys_release (void);
static struct FN *
sys_new (int buf_size);
static void sysnx1 (void);
static void sys_close (register struct FN * fnp, int count);
static void raw_close (int handle);
static int raw_creat (char *name);
static int raw_open (char *name);
static int raw_read (int handle, char *buffer, int n);
static void raw_write (int handle, char *buffer, int n);
/*
Define the format of a file node.
The node contains all information pertaining to the file.
The fil_name and f_line are used to update preprocessor globals.
The f_line field is not used for output files.
*/
static struct FN {
struct FN * f_next; /* pointer to next node */
char * fil_name; /* file name */
int f_line; /* line number */
char * f_buffer; /* file buffer */
int f_bufsize; /* size of file buffer: bytes */
int f_handle; /* File handle. */
char * f_bufp; /* pointer into file buffer */
int f_bufc; /* characters in buffer */
int f_type; /* INPUT, OUTPUT, EOF_STAT, CLOSED */
int f_lastc; /* last character of previous level */
};
#define FN_SIZE (sizeof(struct FN))
static struct FN * in_list; /* List of input nodes. */
static struct FN * outn_list; /* List of output nodes. */
/*
The following global variables are copies of the fields in FN.
Global variables are used as an efficiency measure.
*/
static char * s_ip; /* Copy of f_bufp for input file. */
static int s_ic; /* Copy of f_bufc for input file. */
static char * s_op; /* Copy of f_bufp for output file. */
static int s_oc; /* Copy of f_bufc for output file. */
#define CLOSED 1
#define INPUT 2
#define OUTPUT 3
#define EOF_STAT 3
/*
You may tune the following constants:
MAX_INLEVEL the greatest allowed depth for nested #includes.
IBUF_SIZE size of each input buffer in bytes.
OBUF_SIZE size of the output buffer in bytes.
*/
#define MAX_INLEVEL 20
#define IBUF_SIZE 4096
#define OBUF_SIZE 4096
/*
Close all files and exit.
Do not call fatal() or sysabort() from inside
sysiclose(), sysoclose(), or sys_release().
*/
void
sysabort(void)
{
SL_DISABLE();
/* Close the output file. */
if (outn_list != NULL) {
sysoclose();
}
/* Close all input files. */
while(in_list != NULL) {
sysiclose();
}
sysend();
exit(1);
}
/*
Remove one node from the input list.
*/
static void
sys_release(void)
{
register struct FN * fnp;
TICKB("sys_release");
#ifdef DEBUG
if (in_list == NULL) {
t_error("sys_release: can't happen");
exit(0);
}
#endif
/* Remove the node from the input list. */
fnp = in_list;
in_list = fnp -> f_next;
fnp -> f_type = CLOSED;
/* Deallocate the node. */
if (fnp -> f_buffer != NULL) {
mg_free(fnp -> f_buffer);
}
mg_free( (char *) fnp);
/* Reset the global variables from the next node. */
if (in_list != NULL) {
fnp = in_list;
s_ic = fnp -> f_bufc;
s_ip = fnp -> f_bufp;
}
else {
s_ic = 0;
}
TICKX("sys_release");
}
/*
Allocate space for a new file node, file buffer and FCB.
Fill in all other fields to neutral values.
Return a pointer to the node.
*/
static struct FN *
sys_new(int buf_size)
{
register struct FN * fnp;
TRACEPB("sys_new", printf("(%d)\n", buf_size));
fnp = (struct FN *) mg_alloc(sizeof(struct FN));
fnp -> f_buffer = (char *) mg_alloc(buf_size);
fnp -> f_bufsize = buf_size;
fnp -> f_next = NULL;
fnp -> fil_name = NULL;
fnp -> f_bufp = fnp -> f_buffer;
fnp -> f_bufc = 0;
fnp -> f_type = CLOSED;
fnp -> f_handle = -1;
RETURN_PTR("sys_new", fnp);
}
/*
----- I N P U T L O G I C -----
Set the global variable ch to the next character from the input stream.
The next call to sysnext() will return another character.
This is the most often called routine in the whole program.
*/
#define MAX_MTEXT 2000
static char m_buffer [MAX_MTEXT];
static char * m_oldp;
static int m_oldc;
static int m_flag;
/* this portion of the routine ought to be a macro */
void
sysnext(void)
{
SL_DISABLE();
if (!s_ic) {
sysnx1();
}
else {
s_ic--;
ch = (unsigned char) *s_ip++;
}
}
/* This fills ch when the buffer is empty */
static void
sysnx1(void)
{
register int n;
register struct FN * fnp;
TICKB("sysnx1");
if (m_flag == TRUE) {
/* Close the macro buffer. */
m_flag = FALSE;
/* Restart the previous buffer. */
s_ic = m_oldc;
s_ip = m_oldp;
if (s_ic) {
s_ic--;
ch = (unsigned char) *s_ip++;
RETURN_VOID("sysnx1");
}
}
/* A file buffer is empty. */
fnp = in_list;
switch(fnp -> f_type) {
case EOF_STAT:
ch = END_FILE;
RETURN_VOID("sysnx1");
case INPUT:
n = raw_read(fnp->f_handle, fnp->f_buffer, IBUF_SIZE);
if (n > 0) {
s_ic = n;
s_ip = fnp -> f_buffer;
s_ic--;
ch = (unsigned char) *s_ip++;
RETURN_VOID("sysnx1");
}
else {
fnp -> f_type = EOF_STAT;
ch = END_FILE;
RETURN_VOID("sysnx1");
}
default:
TRACEP("sysnx1",
printf("in_list = %p, in_list -> f_type = %d\n",
in_list, in_list -> f_type));
fatal("sysnext: can't happen");
}
TICKX("sysnx1");
}
/*
Push a character so that it will be returned next by sysnext.
The current value of ch is NOT saved.
*/
void
syspush(int c)
{
SL_DISABLE();
if (m_flag == FALSE) {
TRACEP("syspush", printf("start of macro expansion\n"));
/* Begin to use the macro buffer. */
m_flag = TRUE;
/* Save the old pointers. */
m_oldp = s_ip;
m_oldc = s_ic;
/* Point into the macro buffer. */
s_ip = &m_buffer[MAX_MTEXT-1];
*s_ip = (char) c;
s_ic = 1;
}
else if (s_ic >= MAX_MTEXT) {
fatal("macro expansion too long.");
}
else {
*--s_ip = (char) c;
s_ic++;
}
}
/*
Push a string so that it will be returned next by sysnext.
*/
void
sysspush(register char *s)
{
register char *p;
register int count;
SL_DISABLE();
/* Push in reverse. */
count = str_len(s);
p = s;
p += count;
p--;
while(count-- > 0) {
syspush(*p--);
}
}
/*
Close the current input file and pop back one level.
*/
void
sysiclose(void)
{
register struct FN * fnp;
#ifdef DEBUG
TICKB("sysiclose");
if (t_inlevel < 0) {
t_error("sysiclose: bad t_inlevel");
exit(0);
}
#endif
/* Close the current input file. */
fnp = in_list;
raw_close(fnp -> f_handle);
/* Release the current node. */
sys_release();
if (t_inlevel > 0 && in_list == NULL) {
t_error("sysiclose: null in_list");
exit(0);
}
/* Pop back one level. */
if (in_list != NULL) {
if (t_inlevel < 0) {
t_error("sysiclose: unexpected in_list");
exit(0);
}
fnp = in_list;
s_ic = fnp -> f_bufc;
s_ip = fnp -> f_bufp;
t_file = fnp -> fil_name;
t_line = fnp -> f_line;
}
t_inlevel--;
if (t_inlevel == -1) {
ch = END_FILE;
}
else {
ch = (unsigned char) fnp -> f_lastc;
}
TRACEPX("sysiclose", printf("returns: t_inlevel=%d\n", t_inlevel));
}
/*
Open a file for input.
Return TRUE if all went well.
*/
bool
sysopen(char * name)
{
struct FN * fnp;
char * str_galloc();
TRACEPB("sysopen", printf("(%s) t_inlevel: %d\n", name, t_inlevel));
if (m_flag == TRUE) {
m_flag = FALSE;
t_error("macro expansion truncated following #include");
}
/* Save information about the current level on the stack. */
if (t_inlevel != -1) {
if (in_list == NULL) {
fatal("sysopen: can't happen\n");
}
fnp = in_list;
fnp -> f_line = t_line;
fnp -> f_bufc = s_ic;
fnp -> f_bufp = s_ip;
fnp -> f_lastc = (int) ch;
}
/* Enter a new level. */
if (t_inlevel >= MAX_INLEVEL) {
t_error("include files nested too deeply");
exit(0);
}
else {
t_inlevel++;
}
/* Create a new file node and link to the front of the list. */
TRACEP("sysopen", printf("set up new file: call sys_new\n"));
fnp = sys_new(IBUF_SIZE);
fnp -> f_next = in_list;
in_list = fnp;
fnp -> f_type = INPUT;
/* Actually open the file. */
fnp -> f_handle = raw_open(name);
if (fnp -> f_handle == -1) {
/* Deallocate the node. */
TRACEP("sysopen", printf("file open %s fails\n", name));
sys_release();
t_inlevel--;
RETURN_BOOL("sysopen", FALSE);
}
/* Set the global variables. */
t_file = str_galloc(name);
t_line = 1;
fnp -> fil_name = t_file;
/* Put the first character of the file into ch. */
s_ic = 0;
s_ip = fnp -> f_buffer;
sysnext();
TRACEP("sysopen",
printf("new t_inlevel=%d, in_list=%p\n", t_inlevel, in_list));
RETURN_BOOL("sysopen", TRUE);
}
/*
Close a file opened with raw_open() or raw_creat().
*/
static void
raw_close(int handle)
{
SL_DISABLE();
#ifdef STANDARD_C
close (handle);
#endif
}
/*
Open the file for writing only.
Return -1 on error.
*/
static int
raw_creat(char *name)
{
int h;
#ifdef STANDARD_C
TRACEPB("raw_creat", printf("(%s)\n", name));
chmod(name, S_IREAD | S_IWRITE);
#ifdef TURBOC
_fmode = O_BINARY;
#endif /* TURBOC */
RETURN_INT("raw_creat", creat(name, S_IREAD | S_IWRITE));
#endif
}
/*
Open the file for reading only.
Return -1 on error.
*/
static bool
raw_open(register char *name)
{
#ifdef STANDARD_C
TRACEPB("raw_open", printf("(%s)\n", name));
RETURN_BOOL("raw_open", open(name, O_RDONLY | O_BINARY));
#endif
}
/*
Read n bytes from the file fd into buffer[].
Return the number of bytes read.
*/
static int
raw_read(int handle, char *buffer, int n)
{
#ifdef STANDARD_C
TRACEPB("raw_read", printf("(%d, %s, %d)\n", handle, buffer, n));
RETURN_INT("raw_read", read (handle, buffer, n));
#endif
}
/*
Write n bytes from buffer[] to the file fd.
Return the number of bytes written or -1 for error.
*/
static void
raw_write(int handle, char *buffer, int n)
{
TRACEPB("raw_write", printf("(%d, %s, %d)\n", handle, buffer, n));
#ifdef STANDARD_C
(void) write (handle, buffer, n);
#endif
TICKX("raw_write");
}
/*
----- OUTPUT LOGIC -----
*/
/*
Open a file for output. Only one such file may be open at a time.
Return TRUE if all went well.
*/
bool
syscreat(register char * name)
{
register struct FN * fnp;
TRACEPB("syscreat", printf("(%s)\n", name));
fnp = outn_list;
#ifdef DEBUG
if (fnp == NULL || fnp -> f_type != CLOSED) {
fatal("syscreat: can't happen");
}
#endif
/* Actually open the file. */
fnp -> f_handle = raw_creat(name);
if (fnp -> f_handle == -1) {
RETURN_BOOL("syscreat", FALSE);
}
fnp -> f_type = OUTPUT;
/* The output buffer is empty. */
s_oc = 0;
s_op = fnp -> f_buffer;
RETURN_BOOL("syscreat", TRUE);
}
/*
Close the output file(s).
*/
void
sysoclose(void)
{
register struct FN * fnp;
TICKB("sysoclose");
fnp = outn_list;
if (fnp != NULL && fnp -> f_type != CLOSED) {
syscput(END_FILE);
sys_close(fnp, s_oc);
}
TICKX("sysoclose");
}
static void
sys_close(register struct FN * fnp, int count)
{
TRACEPB("sys_close", printf("(%p, %d)\n", fnp, count));
/* Finish writing the last sector(s). */
if (count) {
raw_write(fnp->f_handle, fnp->f_buffer, count);
}
/* Close the file. */
raw_close(fnp -> f_handle);
fnp -> f_type = CLOSED;
TICKX("sys_close");
}
/*
Put a newline to the output file.
*/
void
sysnlput(void)
{
struct FN * fnp;
SL_DISABLE();
*s_op++ = '\r';
s_oc++;
if (s_oc == OBUF_SIZE) {
fnp = outn_list;
raw_write(fnp->f_handle, fnp->f_buffer, OBUF_SIZE);
s_op = fnp -> f_buffer;
*s_op++ = '\n';
s_oc = 1;
}
else {
*s_op++ = '\n';
s_oc++;
if (s_oc == OBUF_SIZE) {
fnp = outn_list;
raw_write(fnp->f_handle, fnp->f_buffer, OBUF_SIZE);
s_oc = 0;
s_op = fnp -> f_buffer;
}
}
/* Give user a chance to stop. */
(void) syscsts();
}
/*
Put a non-newline to the output file.
This is the most called routine after sysnext().
*/
void
syscput(char c)
{
struct FN * fnp;
SL_DISABLE();
#ifdef DEBUG
if (c == '\n') {
printf("syscput: shouldn't happen\n");
sysnlput();
return;
}
#endif
*s_op++ = c;
s_oc++;
if (s_oc == OBUF_SIZE) {
fnp = outn_list;
raw_write(fnp->f_handle, fnp->f_buffer, OBUF_SIZE);
s_oc = 0;
s_op = fnp -> f_buffer;
}
}
/*
Put one string to the output file.
*/
void
syssput(register char * s)
{
SL_DISABLE();
while (*s) {
syscput(*s++);
}
}
/*
Shut down the system. This routine is called just before doing an
exit(0). Do any last minute things here.
*/
void
sysend(void)
{
TICK("sysend");
}
/*
Initialize the system module. This routine is called just once before
any other calls to this module. Do any initilizing here.
*/
void
sysinit(void)
{
register struct FN * fnp;
TICKB("sysinit");
/* Portable part. */
t_inlevel = -1;
t_line = 0;
t_file = NULL;
in_list = NULL;
m_flag = FALSE;
/* Allocate node for output file. */
outn_list = sys_new(OBUF_SIZE);
TRACEPX("sysinit", printf("outn_list = %p\n", outn_list));
}
/*
Return 0 if no character is ready from the keyboard.
Otherwise, return the character itself.
*/
int
syscsts(void)
{
SL_DISABLE();
#ifdef STANDARD_C
if (kbhit()) {
return fgetchar() & 0x7f;
}
else {
return 0;
}
#endif
}